home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / infosrvr / dev / libhtml_.tar / HTMLwriter.c < prev    next >
C/C++ Source or Header  |  1993-01-21  |  4KB  |  206 lines

  1. /* HTMLwriter.c -- HTML output for WWW nodes
  2.  * $Id: SGMLmain.c,v 1.3 93/01/06 18:40:27 connolly Exp Locker: connolly $
  3.  */
  4.  
  5. /* implements ... */
  6. #include "HTMLwriter.h"
  7.  
  8. /* uses ... */
  9. #include "HTMLdtd.h"
  10. #include "SGML.h"
  11.  
  12. #include <string.h>
  13. #include "object.h"
  14.  
  15. /* prototypes for private functions... */
  16.  
  17. static HMWriterProc htmlwriter_new;
  18. static HMDeleteProc htmlwriter_dt;
  19.  
  20. static HMStartTagProc start_tag;
  21. static HMEndTagProc end_tag;
  22. static HMDataProc data;
  23.  
  24. HMDoc_Class HTMLwriter = {0, htmlwriter_new, htmlwriter_dt,
  25.                 start_tag, end_tag, data,
  26.               html_entity_text};
  27.  
  28. typedef struct{
  29.   HMStream out;
  30.   HMWriteProc *write;
  31.   enum {start, html, head, body} state;
  32. }STR;
  33.  
  34.  
  35. #define STR_puts(s, chars) ((s)->write)((s)->out, (chars), strlen(chars));
  36.  
  37. static HMDoc*
  38.   htmlwriter_new(out, write)
  39. HMStream out;
  40. HMWriteProc* write;
  41. {
  42.   STR* s = NEW(STR, 1);
  43.   s->out = out;
  44.   s->write = write;
  45.   s->state = start;
  46.  
  47.   return (HMDoc*)s;
  48. }
  49.  
  50. static VOID
  51.   htmlwriter_dt(this)
  52. HMDoc* this;
  53. {
  54.   FREE(this);
  55. }
  56.  
  57.  
  58. static VOID
  59. data(document, chars, nchars)
  60.      HMDoc* document;
  61.      CONST char* chars;
  62.      int nchars;
  63. {
  64.   STR* s = (STR*)document;
  65.   char* out;
  66.  
  67.   if(nchars>0){
  68.     int len;
  69.     
  70.     /* fake tag minimization.
  71.      * This is a non-conforming error handling mechanism.
  72.      * But it's expedient.
  73.      */
  74.     switch(s->state){
  75.     case start:
  76.       start_tag(document, "HTML", 0, 0);
  77.     case html:
  78.       start_tag(document, "BODY", 0, 0);
  79.       break;
  80.       
  81.     case head:
  82.       return; /* data in HEAD tag is an error */
  83.  
  84.     }
  85.  
  86.     len = SGML_replen(chars, "<>&");
  87.     out = NEW(char, len + 1);
  88.     SGML_repcpy(out, chars, "<>&");
  89.     (s->write)(s->out, (VOIDPTR)out, (unsigned)len);
  90.     FREE(out);
  91.   }
  92. }
  93.  
  94.  
  95. static VOID
  96. end_tag(document, gi)
  97.      HMDoc* document;
  98.      CONST char* gi;
  99. {
  100.   STR* s = (STR*)document;
  101.   /*
  102.    * This is a non-conforming error handling mechanism.
  103.    * But it's expedient.@@
  104.    */
  105.   if(!strcmp(gi, "HEAD")
  106.      || !strcmp(gi, "BODY"))
  107.     s->state = html;
  108.   else if (!strcmp(gi, "HTML"))
  109.     s->state = start;
  110.  
  111.   (s->write)(s->out, "\n</", 3);
  112.   STR_puts(s, gi);
  113.   (s->write)(s->out, ">", 1);
  114. }
  115.  
  116.  
  117. static int
  118. start_tag(document, gi, attributes, nattrs)
  119.      HMDoc* document;
  120.      CONST char* gi;
  121.      CONST HMBinding attributes[];
  122.      int nattrs;
  123. {
  124.   STR* s = (STR*)document;
  125.   int i, len;
  126.   char literal[SGML_LITLEN*6];
  127.   int content = HTML_content(gi);
  128.  
  129.   /* @@ fake tag minimization */
  130.   if(!strcmp(gi, "HTML"))
  131.     s->state = html;
  132.  
  133.   if(!strcmp(gi, "HEAD"))
  134.     s->state = head;
  135.   else if (!strcmp(gi, "BODY"))
  136.     s->state = body;
  137.  
  138.   (s->write)(s->out, "<", 1);
  139.   STR_puts(s, gi);
  140.   for(i = 0; i<nattrs; i++){
  141.     CONST char* name = attributes[i].name;
  142.  
  143.     len = SGML_replen(attributes[i].value, "\"&");
  144.     SGML_repcpy(literal, attributes[i].value, "\"&");
  145.     (s->write)(s->out, " ", 1);
  146.     STR_puts(s, name);
  147.     (s->write)(s->out, "=\"", 2);
  148.     STR_puts(s, literal);
  149.     (s->write)(s->out, "\"", 1);
  150.   }
  151.  
  152.   /* only write out newline for non-empty elements */
  153.   (s->write)(s->out, ">\n", content == SGML_EMPTY ? 1 : 2);
  154.  
  155.   return content;
  156. }
  157.  
  158. /*********************
  159.  * Data routines
  160.  *********************/
  161.  
  162. int
  163.   SGML_replen(data, specials)
  164. CONST char* data;
  165. CONST char* specials;
  166. {
  167.   CONST unsigned char* p = (CONST unsigned char*)data;
  168.   int ret = strlen(data);
  169.  
  170.   while(*p){
  171.     if(strchr(specials, *p))
  172.       ret += (*p>9 ? (*p>99 ? 5 : 4) : 3); /* extra &#ddd; */
  173.     *p++;
  174.   }
  175.   return ret;
  176. }
  177.  
  178.  
  179. char*
  180.   SGML_repcpy(markup, data, specials)
  181. char* markup;
  182. CONST char* data;
  183. CONST char* specials;
  184. {
  185.   char* dst = markup;
  186.   CONST unsigned char* p = (CONST unsigned char*)data;
  187.   char digit;
  188.  
  189.   while(*p){
  190.     if(strchr(specials, *p)){
  191.       *dst++ = '&'; /* @@ non-ascii compilers! */
  192.       *dst++ = '#';
  193.       if(*p > 99)
  194.     *dst++ = (*p / 100) + '0';
  195.       if(*p > 9)
  196.     *dst++ = ((*p % 100) / 10) + '0';
  197.       *dst++ = (*p % 10) + '0';
  198.       *dst++ = ';';
  199.       p++;
  200.     }else
  201.       *dst++ = *p++;
  202.   }
  203.   *dst = 0;
  204.   return markup;
  205. }
  206.